package com.study.minio.service.impl;

import com.study.minio.dao.mapper.OpenEmptyCardOrderMapper;
import com.study.minio.repository.OpenEmptyCardOrderRepository;
import com.study.minio.service.MysqlLogReadService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.*;

/**
 * mysqlbinlog读取
 */
@Service
public class MysqlLogReadServiceImpl implements MysqlLogReadService {


    @Autowired
    private OpenEmptyCardOrderRepository openEmptyCardOrderRepository;

    private Map<String, Map<String, String>> columnsMap = new HashMap<>();

    private Set<String> setTable = new HashSet<>();

    public MysqlLogReadServiceImpl() {
        setTable.add("ib_kameng_deliveryrecord");
        setTable.add("ib_kameng_deliveryrecord_2");
        setTable.add("ib_kameng_deliveryrecord_5");
        setTable.add("ib_kameng_deliveryrecord_6");
        setTable.add("ib_kameng_deliveryrecord_7");
        setTable.add("order_audited");
        setTable.add("order_audit_log");
        setTable.add("order_audit_afterwards");
        setTable.add("t_newasync_log");
        setTable.add("tb_activate_log");
        setTable.add("tb_activation_pre_audit_log");
        setTable.add("tb_additional_order");
        setTable.add("tb_adultcard_order");
        setTable.add("tb_apply_power");
        setTable.add("tb_audit_log");
        setTable.add("tb_back_record_audit");
        setTable.add("tb_black_idcard");
        setTable.add("tb_black_user");
        setTable.add("tb_card_resource");
        setTable.add("tb_deduction_detail");
        setTable.add("tb_deduction_detail_statistics");
        setTable.add("tb_freeazen_merchant");
        setTable.add("tb_freezen_device");
        setTable.add("tb_freezon_phone");
        setTable.add("tb_id_back_record");
        setTable.add("tb_idcard_log");
        setTable.add("tb_imsi_resource");
        setTable.add("tb_income_stats");
        setTable.add("tb_inforecorde_order");
        setTable.add("tb_inforecorde_order_audit");
        setTable.add("tb_job_number_audit");
        setTable.add("tb_job_number_audit_log");
        setTable.add("tb_jyb_order");
        setTable.add("tb_jyb_with_recharge_phone");
        setTable.add("tb_kameng_sync");
        setTable.add("tb_living_log");
        setTable.add("tb_login_living_record");
        setTable.add("tb_makecard_time");
        setTable.add("tb_makepre_stats");
        setTable.add("tb_makepre_stats_try");
        setTable.add("tb_makewhite_stats");
        setTable.add("tb_makewhite_stats_try");
        setTable.add("tb_merchant");
        setTable.add("tb_merchant_account");
        setTable.add("tb_merchant_account_detail");
        setTable.add("tb_merchant_account_detail_statistics");
        setTable.add("tb_merchant_act_stats");
        setTable.add("tb_merchant_change_address");
        setTable.add("tb_merchant_change_address_record");
        setTable.add("tb_merchant_detail");
        setTable.add("tb_merchant_incr_stats");
        setTable.add("tb_merchant_info_fill");
        setTable.add("tb_merchant_no_super");
        setTable.add("tb_merchant_perfection_log");
        setTable.add("tb_merchant_perfection_record");
        setTable.add("tb_merchant_scope_config");
        setTable.add("tb_merchant_shqp");
    }

    Set<String> tableNameSet = new HashSet<>();

    @Override
    public void process(String inputFile) {
        //mysqlbinlog --base64-output=decode-rows -v /home/mysql_log/mysql-bin.000901  > /home/mysql_log/mysql-bin.000901.txt
        largeFileIO(inputFile);
        columnsMap.clear();
        System.out.println("表个数:"+tableNameSet.size());
        for(String str: tableNameSet){
            System.out.println(str);
        }
        tableNameSet.clear();
    }



    private void read() throws IOException {
        String path = "E:\\mysql_log\\mysql-bin.000333.txt";
        //// 这里rw看你了。要是之都就只写r
        try (RandomAccessFile br = new RandomAccessFile(path, "r");) {
            String line;
            List<Entity> lineList = new ArrayList<>();
            long i = 0;
            while ((line = br.readLine()) != null) {
                i++;
                //System.out.println(line);

                if (line.startsWith("SET TIMESTAMP=")) {
                    Entity entity = new Entity();
                    entity.setTimestamp(line.substring(line.indexOf("=") + 1, "SET TIMESTAMP=1623310086".length()));

                    lineList.add(entity);
                    if (lineList.size() > 1) {
                        System.out.println(lineList.get(lineList.size() - 2));
                    }
                    continue;
                }
                if (line.startsWith("###")) {
                    Entity entity = lineList.get(lineList.size() - 1);

                    String str = entity.getSql() + line.substring(3);
                    str = new String(str.getBytes("UTF-8"), "gbk");
                    ;

//                    lineList.get(lineList.size() - 1).setSql(str);
                }
            }
            br.close();
        }
    }

    // 当逐行读写大于2G的文本文件时推荐使用以下代码
    public void largeFileIO(String inputFile) {
        //String inputFile = "E:\\mysql_log\\mysql-bin.000333.txt";

        File file = new File(inputFile);
        String outputFile = inputFile.replace(".txt", "_2.sql");
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
             BufferedReader in = new BufferedReader(new InputStreamReader(bis, "utf-8"), 100 * 1024 * 1024);// 10M缓存
        ) {
            //FileWriter fw = new FileWriter(outputFile);
            Writer fw = new BufferedWriter(
                    new OutputStreamWriter(
                            new FileOutputStream(outputFile), "UTF-8"));
            Entity entity = null;
            String line;
            while (in.ready()) {
                line = in.readLine();
                //System.out.println(line);

                if (line.startsWith("SET TIMESTAMP=")) {
//                    entity = new Entity();
//                    entity.setTimestamp(line.substring(line.indexOf("=") + 1, "SET TIMESTAMP=1623310086".length()));

                    long time = Long.valueOf(line.substring(line.indexOf("=") + 1, "SET TIMESTAMP=1623310086".length()));
                    if(time > 1623309300L) {
                        break;
                    }
                }

                if (line.startsWith("###")) {
                    final String str = line.substring(3).trim();

                    if (str.startsWith("UPDATE") || str.startsWith("INSERT") || str.startsWith("DELETE")) {
                        if (Objects.nonNull(entity)) {
                            if (!Objects.equals("ha_health_check", entity.getTableName())) {
//                                if(Long.valueOf(entity.getTimestamp())< 1623395520L) {
                                    for (String tableName : setTable) {
                                        if (entity.getTableName().contains(tableName)) {
                                            fw.write(parseSql(entity.getSql().toString()) + ";\r\n");
                                            tableNameSet.add(entity.getTableName());
                                            break;
                                        }
                                    }
//                                }
                            }

                            entity.setTableName(null);
                            entity.getSql().delete(0, entity.getSql().length());
                        }
                        else{
                            entity = new Entity();
                        }
                    }

                    //获取第一行
                    if (Objects.isNull(entity.getTableName())) {
                        entity.getSql().append(str.replace("`kameng`.",""));
                        entity.setTableName(str.substring(str.indexOf(".") + 1));
                        if (Objects.equals("`ha_health_check`", entity.getTableName())) {
                            continue;
                        }
                        if (!columnsMap.containsKey(entity.getTableName())) {
                            List<String> tableColumns = openEmptyCardOrderRepository.showColumns(entity.getTableName());
                            Map<String, String> columns = new HashMap<>();
                            int i = 1;
                            for (String columnName : tableColumns) {
                                columns.put("@" + i, "`"+columnName+"`");
                                i++;
                            }

                            columnsMap.put(entity.getTableName(), columns);
                        }
                        continue;
                    }

                    if (!str.contains("=")) {
                        entity.getSql().append(" " + str);
                        continue;
                    }

                    if (Objects.equals("`ha_health_check`", entity.getTableName())) {
                        continue;
                    }

                    //获取其余行 @num=x
                    String array[] = str.split("=");
                    Map<String, String> map = columnsMap.get(entity.getTableName());
                    if (Objects.isNull(array[0]) || Objects.isNull(map.get(array[0]))) {
                        System.out.println(str);
                    }
                    entity.getSql().append(" " + str.replace(array[0], map.get(array[0])) + " ");
                }
            }
            in.close();
            fw.flush();
            fw.close();
            System.out.println("执行完文件" + inputFile);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }


    @Data
    public class Entity {
        private String timestamp;
        private String tableName;
        private StringBuilder sql = new StringBuilder();

        @Override
        public String toString() {
            return timestamp + " " + sql;
        }
    }

    private String parseSql(String str){
        //System.out.println(str);
        if(str.startsWith("UPDATE")){
            int indexSet = str.indexOf("SET");
            int indexWhere = str.indexOf("WHERE");

            String setCondition = str.substring(indexSet+"SET".length());
            String whereCondition = str.substring(indexWhere+"WHERE".length() ,indexSet);

            StringBuilder sb = new StringBuilder(128);
            sb.append(str.substring(0,indexWhere));
            sb.append(" SET ");
            int i = 0;
            for(String cond :  setCondition.split("  ")) {
                if(cond.trim().length() == 0){
                    continue;
                }

                if(cond.trim().startsWith("`id`=")){
                    continue;
                }
                if(i != 0){
                    sb.append(",");
                }
                sb.append(cond);
                i++;
            }

            sb.append(" WHERE ");
            i = 0;
            for(String cond : whereCondition.split("  ")) {
                if(cond.trim().length() == 0){
                    continue;
                }

                if(cond.trim().startsWith("`id`=")){
                    continue;
                }

                if(i != 0){
                    sb.append(" and ");
                }
                sb.append(cond);
                i++;
            }

            return sb.toString().replace("(4294967295)","");
        }

        if(str.startsWith("INSERT")){
            int indexSet = str.indexOf("SET");
            String condition = str.substring(indexSet + "SET".length());

            StringBuilder sb = new StringBuilder(128);
            sb.append(str.substring(0,indexSet));
            sb.append(" SET ");
            int i = 0;
            for(String cond :  condition.split("  ")) {
                if(cond.trim().length() == 0){
                    continue;
                }

                if(cond.trim().startsWith("`id`=")){
                    continue;
                }

                if(i != 0){
                    sb.append(",");
                }
                sb.append(cond);
                i++;
            }

            return sb.toString().replace("(4294967295)","");
        }

        if(str.startsWith("DELETE")){
            int indexWhere = str.indexOf("WHERE");
            String condition = str.substring(indexWhere + "WHERE".length());

            StringBuilder sb = new StringBuilder(128);
            sb.append(str.substring(0,indexWhere));
            sb.append(" where ");
            int i = 0;
            for(String cond :  condition.split("  ")) {
                if(cond.trim().length() == 0){
                    continue;
                }

                if(cond.trim().startsWith("`id`=")){
                    continue;
                }

                if(i != 0){
                    sb.append(" and ");
                }
                sb.append(cond);
                i++;
            }
            return sb.toString().replace("(4294967295)","");
        }

        System.out.println("error");
        return str;
    }
}